#include "HttpUtil.h"
#include "../config/ConfigManager.h"
#include <QFile>
#include <QTextStream>
#include <QDebug>

#define CONFIG_PATH ":/config/config.json"

HttpUtil::HttpUtil(QObject *parent) : QObject(parent) {
}

HttpUtil &HttpUtil::getInstance() {
    static HttpUtil instance;
    return instance;
}

void HttpUtil::init() {
    if (initialized)
        return;
    loadConfig();
    startServer(configuredPort);
    initialized = true;
    qDebug() << "HttpUtil initialized";
}

void HttpUtil::loadConfig() {
    ConfigManager::instance().loadConfig(CONFIG_PATH);
    configuredPort = ConfigManager::instance().getInt("server.port", 8080);
    autoStart = ConfigManager::instance().getBool("server.autoStart", true);
}

void HttpUtil::startServer(int port) {
    server = new QTcpServer(this);
    connect(server, &QTcpServer::newConnection, this, &HttpUtil::handleNewConnection);
    if (!server->listen(QHostAddress::Any, port)) {
        qCritical() << "Server listen failed on port" << port;
    } else {
        qDebug() << "Server listening on port" << port;
    }
}

void HttpUtil::registerHandler(Method method, const QString &pathPattern, HandlerFunc handler) {
    RouteKey key{method, pathPattern};
    handlers[key] = handler;
    qDebug() << "Registered handler for" << key.pathPattern;
}

void HttpUtil::addRoute(Method method, const QString &pathPattern, HandlerFunc handler) {
    getInstance().registerHandler(method, pathPattern, handler);
}

void HttpUtil::handleNewConnection() {
    QTcpSocket *socket = server->nextPendingConnection();
    connect(socket, &QTcpSocket::readyRead, [this, socket]() { handleReadyRead(socket); });
}

QString HttpUtil::extractMethod(const QString &requestLine) {
    return requestLine.section(' ', 0, 0).trimmed().toUpper();
}

QString HttpUtil::extractPath(const QString &requestLine) {
    return requestLine.section(' ', 1, 1).trimmed();
}

QMap<QString, QString> HttpUtil::extractQuery(const QString &fullPath) {
    QMap<QString, QString> queryParams;
    QString query = fullPath.section('?', 1, 1);
    for (const QString &pair: query.split('&')) {
        QStringList kv = pair.split('=');
        if (kv.size() == 2) {
            queryParams[kv[0]] = kv[1];
        }
    }
    return queryParams;
}

QString HttpUtil::normalizePath(const QString &path) {
    return path.section('?', 0, 0);
}

void HttpUtil::handleReadyRead(QTcpSocket *socket) {
    QByteArray requestData = socket->readAll();
    QString request = QString::fromUtf8(requestData);

    QStringList lines = request.split("\r\n", Qt::SkipEmptyParts);
    if (lines.isEmpty())
        return;

    QString methodStr = extractMethod(lines[0]);
    QString fullPath = extractPath(lines[0]);
    QString purePath = normalizePath(fullPath);
    QMap<QString, QString> query = extractQuery(fullPath);

    Method method;
    if (methodStr == "GET")
        method = Method::GET;
    else if (methodStr == "POST")
        method = Method::POST;
    else if (methodStr == "PUT")
        method = Method::PUT;
    else if (methodStr == "DELETE")
        method = Method::DELETE;
    else {
        qWarning() << "Unsupported method:" << methodStr;
        return;
    }

    QString body = request.section("\r\n\r\n", 1);
    json input;
    try {
        if (!body.trimmed().isEmpty())
            input = json::parse(body.toStdString());
    } catch (...) {
        input = json{{"error", "invalid JSON"}};
    }

    RouteKey key{method, purePath};

    json response;
    if (handlers.contains(key)) {
        try {
            response = handlers[key](purePath, query, input);
        } catch (const std::exception &e) {
            response = json{{"error", e.what()}};
        }
    } else {
        response = json{{"error", "route not found"}};
    }

    QByteArray httpResponse = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n";
    httpResponse += QString::fromStdString(response.dump(4)).toUtf8();
    socket->write(httpResponse);
    socket->disconnectFromHost();
}
